<?php

namespace App\Service\Kms\Poi;

use App\Console\Commands\OpenShop\WgAreaAddGeo;
use App\Enums\OpenShop\FeishuMini\ProgrammingEnum;
use App\Models\Common\MapNationalBrandShopModel;
use App\Models\Common\MapNationalIndustrialParkModel;
use App\Models\Common\MapNationalStreetModel;
use App\Models\Common\MapNationalUniversitiesModel;
use App\Models\Common\MapTownshipPlanAreaModel;
use App\Models\Kms\Album\AlbumResourceModel;
use App\Models\OpenShop\Common\SiteLocationMallModel;
use App\Remote\AMap\AMapPlaceRemote;
use App\Remote\Guanyuan\GuanyuanRemote;
use App\Service\Kms\Common\AMapService;
use App\Service\Kms\KmsBaseService;
use App\Service\OpenShop\Feishu\ConfigService;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;

class PoiService extends KmsBaseService
{

    const PREFIX_TYPE_KFZC            = "KFZC";
    const PREFIX_TYPE_STREET          = "JD";
    const PREFIX_TYPE_TOWNSHIP        = "XZ";
    const PREFIX_TYPE_HIGH_SCHOOL     = "GX";
    const PREFIX_TYPE_MALL            = "SC";
    const PREFIX_TYPE_INDUSTRIAL_PARK = "CYY";

    const PREFIX_TYPE_COMPLEMENT_GOODS   = "COMPLEMENT_GOODS";
    const PREFIX_TYPE_COMPETING_PRODUCTS = "COMPETING_PRODUCTS";

    /**
     * @param array $originalPoi
     * @param array $searchType
     * @param bool $withDetail
     * @return array
     * @throws GuzzleException
     * @throws ValidationException
     */
    public static function handleOriginalPoi(
        array $originalPoi,
        array $searchType = [],
        bool $withDetail = false
    ): array {

        $product = ConfigService::getConfigDetail("kms.poi", "product", 30 * 60)["value"] ?? [];

        $defaultPrefixTypeDetail = collect(array_merge([
            self::PREFIX_TYPE_KFZC            => "夸父门店",
            self::PREFIX_TYPE_STREET          => "街道",
            self::PREFIX_TYPE_TOWNSHIP        => "乡镇",
            self::PREFIX_TYPE_HIGH_SCHOOL     => "高校",
            self::PREFIX_TYPE_MALL            => "商场",
            self::PREFIX_TYPE_INDUSTRIAL_PARK => "产业园",
        ], $product))->when(count($searchType) > 0, function (Collection $query) use ($searchType) {
            return $query->filter(function ($v, $k) use ($searchType) {
                if (in_array($k, $searchType)) {
                    return true;
                }
                return false;
            });
        })->toArray();


        $parseOriginalValFunc = function (string $original) use ($defaultPrefixTypeDetail) {
            $status = $realPrefix = $groupKey = $suffix = $desc = "";
            foreach ($defaultPrefixTypeDetail as $key => $value) {
                if (is_array($value)) {
                    $groupData = attributeGet($value, "list", []);
                    foreach ($groupData as $innerKey) {
                        if (Str::startsWith($original, $innerKey)) {
                            $desc       = attributeGet($value, "text", "");
                            $groupKey   = $key;
                            $realPrefix = $innerKey;
                            $suffix     = (int)str_replace($innerKey, "", $original);
                            break;
                        }
                    }
                } else {
                    $desc = $value;
                    if (Str::startsWith($original, $key)) {
                        $groupKey = $realPrefix = $key;
                        switch ($key) {
                            case self::PREFIX_TYPE_KFZC :
                                $suffix = str_replace($key, "", $original);
                                $status = substr($suffix, 0, 1);
                                $suffix = substr($suffix, 1, strlen($suffix) - 1);
                                break;
                            default:
                                $suffix = str_replace($key, "", $original);
                                break;
                        }
                        break;
                    }
                }

            }
            return [$groupKey, $realPrefix, $desc, $suffix, $status];
        };

        $groupSiteFunc = function (Collection $collection, $relData, $poiType) {
            return $collection->map(function (array $v) use ($relData, $poiType) {
                $v["detail"] = $relData->where("wgNumber", $v["originalVal"])->first();
                if (isset($v["detail"]["lat"]) || isset($v["detail"]["long"])) {
                    $v["detail"]["lat"]  = (string)$v["detail"]["lat"];
                    $v["detail"]["long"] = (string)$v["detail"]["long"];
                }
                $v["detail"]["gradeText"] = ProgrammingEnum::GRADE_MAPPING[attributeGet($v["detail"], "grade",
                        null)] ?? "";
                $v["detail"]["poiType"]   = $poiType;
                return $v;
            });
        };

        return collect($originalPoi)->map(function ($value) use ($parseOriginalValFunc) {
            list($originalVal, $distance, $position) = $value;
            list($groupKey, $prefix, $type, $suffix, $status) = $parseOriginalValFunc($originalVal);
            return [
                "groupKey"    => $groupKey,
                "originalVal" => $originalVal,
                "position"    => $position,
                "distance"    => $distance,
                "prefix"      => $prefix,
                "suffix"      => $suffix,
                "type"        => $type,
                "status"      => $status,
                "statusText"  => ProgrammingEnum::KF_SHOP_STATUS_MAPPING[$status] ?? ""
            ];
        })->where("groupKey", "<>", "")->groupBy("groupKey")
                                    ->when($withDetail, function (Collection $query) use ($groupSiteFunc) {
                                        return $query->map(function (Collection $group, $prefix) use ($groupSiteFunc) {
                                            switch ($prefix) {
                                                case self::PREFIX_TYPE_KFZC:
                                                    $originalRelData = GuanyuanRemote::sourceData("r908e1ee76add42668f1adfc",
                                                        "de01da3ecf39743d895db6c6", [
                                                            [
                                                                'name'        => '铺位号',
                                                                'filterType'  => 'IN',
                                                                'filterValue' => array_map(function ($v) {
                                                                    return (string)$v;
                                                                }, $group->pluck("suffix")->toArray()),
                                                            ]
                                                        ]);

                                                    $relData = collect($originalRelData["data"] ?? [])->map(function ($row) {
                                                        return [
                                                            "id"         => $row[4],
                                                            "name"       => $row[5],
                                                            "province"   => $row[10],
                                                            "city"       => $row[11],
                                                            "district"   => $row[12],
                                                            "lat"        => $row[58],
                                                            "long"       => $row[57],
                                                            "address"    => $row[14],
                                                            "statusText" => $row[6],
                                                            "wgNumber"   => vsprintf("%s%s",
                                                                [self::PREFIX_TYPE_KFZC, $row[4]])
                                                        ];
                                                    })->values();
                                                    $group   = $group->map(function (array $v) use ($relData) {
                                                        $detail = $relData->where("id", $v["suffix"])->first() ?? [];
                                                        if($detail){
                                                            $v["detail"] = array_merge(
                                                                $detail,
                                                                ["poiType" => AlbumResourceModel::POI_TYPE_WG_KF_SHOP]
                                                            );
                                                        }else{
                                                            $v["detail"] = [];
                                                        }
                                                        return $v;
                                                    })->filter(function($v){
                                                        if($v["detail"]){
                                                            return true;
                                                        }
                                                        return false;
                                                    })->values();
                                                    break;
                                                case self::PREFIX_TYPE_HIGH_SCHOOL://高校
                                                    $relData = MapNationalUniversitiesModel::query()
                                                                                           ->whereIn("wgNumber",
                                                                                               $group->pluck("originalVal")
                                                                                                     ->toArray())
                                                                                           ->select([
                                                                                               "id",
                                                                                               "wgNumber",
                                                                                               "name",
                                                                                               "province",
                                                                                               "city",
                                                                                               "district",
                                                                                               "lat",
                                                                                               "lon as long",
                                                                                               "grade"
                                                                                           ])
                                                                                           ->get();

                                                    $group = $groupSiteFunc(
                                                        $group,
                                                        $relData,
                                                        AlbumResourceModel::POI_TYPE_WG_HIGH_SCHOOL
                                                    );
                                                    break;
                                                case self::PREFIX_TYPE_INDUSTRIAL_PARK://产业园
                                                    $relData = MapNationalIndustrialParkModel::query()
                                                                                             ->whereIn("wgNumber",
                                                                                                 $group->pluck("originalVal")
                                                                                                       ->toArray())
                                                                                             ->select([
                                                                                                 "id",
                                                                                                 "wgNumber",
                                                                                                 "name",
                                                                                                 "province",
                                                                                                 "city",
                                                                                                 "district",
                                                                                                 "lat",
                                                                                                 "lon as long",
                                                                                                 "name as address",
                                                                                                 "grade"
                                                                                             ])
                                                                                             ->get();
                                                    $group   = $groupSiteFunc($group, $relData,
                                                        AlbumResourceModel::POI_TYPE_WG_INDUSTRIAL_PARK);
                                                    break;
                                                case self::PREFIX_TYPE_MALL:
                                                    $relData = SiteLocationMallModel::query()
                                                                                    ->whereIn("wgNumber",
                                                                                        $group->pluck("originalVal")
                                                                                              ->toArray())
                                                                                    ->select([
                                                                                        "id",
                                                                                        "wgNumber",
                                                                                        "province",
                                                                                        "city",
                                                                                        "district",
                                                                                        "lat",
                                                                                        "lng as long",
                                                                                        "mallName as name",
                                                                                        "address",
                                                                                        "grade"
                                                                                    ])
                                                                                    ->get();
                                                    $group   = $groupSiteFunc($group, $relData,
                                                        AlbumResourceModel::POI_TYPE_WG_MALL);
                                                    break;
                                                case self::PREFIX_TYPE_TOWNSHIP:
                                                    $relData = MapTownshipPlanAreaModel::query()
                                                                                       ->whereIn("wgNumber",
                                                                                           $group->pluck("originalVal")
                                                                                                 ->toArray())
                                                                                       ->select([
                                                                                           "id",
                                                                                           "wgNumber",
                                                                                           "area as name",
                                                                                           "grade",
                                                                                           "province",
                                                                                           "city",
                                                                                           "district",
                                                                                           "lat",
                                                                                           "lng as long",
                                                                                           "address"
                                                                                       ])
                                                                                       ->get();
                                                    $group   = $groupSiteFunc($group, $relData,
                                                        AlbumResourceModel::POI_TYPE_WG_TOWNSHIP);
                                                    break;
                                                case self::PREFIX_TYPE_STREET:
                                                    $relData = MapNationalStreetModel::query()
                                                                                     ->whereIn("wgNumber",
                                                                                         $group->pluck("originalVal")
                                                                                               ->toArray())
                                                                                     ->select([
                                                                                         "id",
                                                                                         "wgNumber",
                                                                                         "name",
                                                                                         "grade",
                                                                                         "province",
                                                                                         "city",
                                                                                         "district",
                                                                                         "lat",
                                                                                         "lng as long",
                                                                                         "address"
                                                                                     ])
                                                                                     ->get();
                                                    $group   = $groupSiteFunc($group, $relData,
                                                        AlbumResourceModel::POI_TYPE_WG_STREET);
                                                    break;
                                                case self::PREFIX_TYPE_COMPETING_PRODUCTS:
                                                    $relData = MapNationalBrandShopModel::query()
                                                                                        ->whereIn("id",
                                                                                            $group->pluck("suffix")
                                                                                                  ->toArray())
                                                                                        ->select([
                                                                                            "id",
                                                                                            "name",
                                                                                            "address",
                                                                                            "brand",
                                                                                            "province",
                                                                                            "city",
                                                                                            "district",
                                                                                            "lat",
                                                                                            "lon as long",
                                                                                        ])
                                                                                        ->get();
                                                    $group   = $group->map(function (array $v) use ($relData) {
                                                        $detail      = $relData->where("id", $v["suffix"])->first()
                                                                               ->toArray();
                                                        $v["detail"] = array_merge(
                                                            $detail,
                                                            [
                                                                "poiType"  => AlbumResourceModel::POI_TYPE_WG_COMPETING_PRODUCTS,
                                                                "wgNumber" => (string)attributeGet($detail, "id", "")
                                                            ]
                                                        );
                                                        return $v;
                                                    });
                                                    break;
                                                case self::PREFIX_TYPE_COMPLEMENT_GOODS:
                                                    $relData = MapNationalBrandShopModel::query()
                                                                                        ->whereIn("id",
                                                                                            $group->pluck("suffix")
                                                                                                  ->toArray())
                                                                                        ->select([
                                                                                            "id",
                                                                                            "name",
                                                                                            "address",
                                                                                            "brand",
                                                                                            "province",
                                                                                            "city",
                                                                                            "district",
                                                                                            "lat",
                                                                                            "lon as long",
                                                                                        ])
                                                                                        ->get();
                                                    $group   = $group->map(function (array $v) use ($relData) {
                                                        $detail      = $relData->where("id", $v["suffix"])->first()
                                                                               ->toArray();
                                                        $v["detail"] = array_merge(
                                                            $detail,
                                                            [
                                                                "poiType"  => AlbumResourceModel::POI_TYPE_WG_COMPLEMENT_GOODS,
                                                                "wgNumber" => (string)(attributeGet($detail, "id", ""))
                                                            ]
                                                        );
                                                        return $v;
                                                    });
                                                    break;
                                            }
                                            return $group;
                                        });
                                    })->toArray();
    }


    /**
     * @param object $params
     * @return array|void
     * @throws ValidationException|GuzzleException
     */
    public static function list(object $params)
    {
        try {
            if (
                empty($radius = attributeGet($params, "radius", ""))
                ||
                empty($unit = attributeGet($params, "unit", ""))
            ) {
                $recommendDistance = ConfigService::getConfigDetail(
                        "kms.poi",
                        "recommendDistance",
                        60 * 30
                    )["value"] ?? [];
                $radius            = $recommendDistance["kf"]["radius"];
                $unit              = $recommendDistance["kf"]["unit"];
            }

            $originalPoi = getRedisClient()->georadius(
                WgAreaAddGeo::GEO_WG_KEY,
                $params->lng,
                $params->lat,
                $radius,
                $unit,
                ['WITHDIST', 'ASC', 'WITHCOORD']
            );

            if (!empty($originalPoi)) {
                $handledPoi = self::handleOriginalPoi($originalPoi, attributeGet($params, "searchType", []), true);
            } else {
                $handledPoi = new \stdClass();
            }

            return [
                "lng"                                              => $params->lng,
                "lat"                                              => $params->lat,
                "radius"                                           => $radius,
                "unit"                                             => $unit,
                "isEmpty"                                          => empty($originalPoi),
                AlbumResourceModel::POI_TYPE_WG_KF_SHOP            => attributeGet($handledPoi, self::PREFIX_TYPE_KFZC,
                    []),//夸父门店
                "wgPoi"                                            => [
                    AlbumResourceModel::POI_TYPE_WG_MALL            => attributeGet($handledPoi, self::PREFIX_TYPE_MALL,
                        []),
                    //商场
                    AlbumResourceModel::POI_TYPE_WG_TOWNSHIP        => attributeGet($handledPoi,
                        self::PREFIX_TYPE_TOWNSHIP,
                        []),
                    //乡镇
                    AlbumResourceModel::POI_TYPE_WG_STREET          => attributeGet($handledPoi,
                        self::PREFIX_TYPE_STREET, []),
                    //街道
                    AlbumResourceModel::POI_TYPE_WG_HIGH_SCHOOL     => attributeGet($handledPoi,
                        self::PREFIX_TYPE_HIGH_SCHOOL,
                        []),
                    //高校
                    AlbumResourceModel::POI_TYPE_WG_INDUSTRIAL_PARK => attributeGet($handledPoi,
                        self::PREFIX_TYPE_INDUSTRIAL_PARK, []),
                    //产业园
                ],
                AlbumResourceModel::POI_TYPE_WG_COMPLEMENT_GOODS   => attributeGet($handledPoi,
                    self::PREFIX_TYPE_COMPLEMENT_GOODS, []),//互补品
                AlbumResourceModel::POI_TYPE_WG_COMPETING_PRODUCTS => attributeGet($handledPoi,
                    self::PREFIX_TYPE_COMPETING_PRODUCTS, []),//竞品
            ];
        } catch (\Exception $exception) {
            handleException($exception, null, (array)$params, "获取夸父poi列表失败");
        }
    }

    /**
     * @param object $params
     * @param int $page
     * @param int $pageSize
     * @return array|void
     * @throws GuzzleException
     * @throws ValidationException
     */
    public static function aMapList(object $params, int $page, int $pageSize)
    {
        try {
            if (
                empty($radius = attributeGet($params, "radius", ""))
                ||
                empty($unit = attributeGet($params, "unit", ""))
            ) {
                $recommendDistance = ConfigService::getConfigDetail(
                        "kms.poi",
                        "recommendDistance",
                        60 * 30
                    )["value"] ?? [];
                $radius            = $recommendDistance["aMap"]["radius"];
                $unit              = $recommendDistance["aMap"]["unit"];
            }


            list($searchCode, $typeDetail) = AMapService::getAMapPoiSearchCode($params->type);
            $aMapPoiRemote = AMapPlaceRemote::around(
                $params->lng,
                $params->lat,
                $searchCode,
                $radius * (["km" => 1000, "m" => 1][$unit]),
                $page,
                $pageSize
            );

            return [
                "lng"     => $params->lng,
                "lat"     => $params->lat,
                "radius"  => $radius,
                "unit"    => $unit,
                "aMapPoi" => array_merge(
                    $typeDetail,
                    [
                        "page"      => (int)$page,
                        "pageSize"  => (int)$pageSize,
                        "total"     => (int)$aMapPoiRemote["count"],
                        "pageCount" => (int)count($aMapPoiRemote["pois"]),
                        "list"      => collect($aMapPoiRemote["pois"])->map(function ($v) use ($params) {
                            return array_merge($v, [
                                "address" => is_array($v["address"]) ? "" : $v["address"],
                                "poiType" => $params->type
                            ]);
                        })->values()->toArray()
                    ]
                )
            ];

        } catch (\Exception $exception) {
            handleException($exception, null, (array)$params, "获取aMap-poi列表失败");
        }
    }
}
